/* ----------------------------------------------------------------------------------------------------------------------
 * ProcessManager
 * -----------------------------------------------------------------------------------------------------------------------
 */
package pure.engine.system 
{
	import flash.display.Shape;
    import flash.events.Event;
    import flash.utils.getTimer;
	import pure.debug.Logger;
	import pure.utils.DesN;
	import pure.utils.DesU;
	import pure.engine.system.ns_despair;

	use namespace ns_despair;
	
	// [Internal]
	
	// 进程管理器
	// [Author] - PURE
	//
public class ProcessManager
{

	
	
	
	
	//======================
	// Base
	//======================
	
	
	// 开始
	ns_despair function start():void
	{
		if (m_started) 
		{
			trace("start", "The ProcessManager is already started.");
			return;
		}
		
		m_started  =  true;
		m_oldTime  =  -1.0;
		m_elapsed  =  0.0;
		Logger.reportMessage(this, "进程启动 !!");
		
		shape.addEventListener(Event.ENTER_FRAME, ____onEnterFrame, false, 10, true);
	}
	
	
	// 停止
	ns_despair function stop():void
	{
		if (!m_started)
		{
			trace("stop", "The ProcessManager isn't started.");
			return;
		}
		m_started = false;
		Logger.reportMessage(this, "进程停止 !!");
		shape.removeEventListener(Event.ENTER_FRAME, ____onEnterFrame);
	}

	
	// 强制更新指定时间
	//ns_despair function tryAdvance(amount:Number):void
	//{
		//advance(amount * m_timeScale, true);
	//}
	

	
	
	
	/* ----------------------------------------------------------------------------------------------------------------------
	 * ★★★★★★★★★★★★★★★★  private  ★★★★★★★★★★★★★★★★
	 * ----------------------------------------------------------------------------------------------------------------------
	 */
	
	

	
	// 单例
	ns_despair static function get instance():ProcessManager 
	{
		return _instance || (_instance = new ProcessManager());
	}
	private static var _instance:ProcessManager
	

	// 加入帧对象
	ns_despair function addFrameObject(object:IFrameObject, priority:Number = 0.0):void
	{
		addObject(object, priority, m_frameObjects, cachedF);
	}

	
	// 移除帧对象
	ns_despair function removeFrameObject(object:IFrameObject):void
	{
		removeObject(object, m_frameObjects);
	}
	
	
	// 加入计时对象
	ns_despair function addTickObject(object:ITickObject, priority:Number = 0.0):void
	{
		addObject(object, priority, m_tickedObjects, cachedT);
	}

	
	// 移除计时对象
	ns_despair function removeTickObject(object:ITickObject):void
	{
		removeObject(object, m_tickedObjects);
	}
	
	
	// 加入对象
	private function addObject(object:*, priority:Number, list:Vector.<ProcessObject>, waitedList:Vector.<ProcessObject>):void
	{
		var processObject:ProcessObject;
		
		if (!m_started)
		{
			start();
		}
		
		// 更新时，加入等待列表
		if(m_duringAdvance)
		{
			m_needAdded             =  true;
			processObject           =  new ProcessObject();
			processObject.listener  =  object;
			processObject.priority  =  priority;
			waitedList.push(processObject);
		}
		else
		{
			_insertObject(object, priority, list);
		}
	}
	
	
	// 插入对象
	private function _insertObject(object:*, priority:Number, list:Vector.<ProcessObject>):void
	{
		var processObject:ProcessObject;
		var len:int, position:int, i:int;
		
		position = -1;
		len = list.length;
		for (i = 0; i < len; i++)
		{
			if (list[i].listener == object) 
			{
				trace("AddProcessObject", "This object has already been added to the process manager.");
				return;
			}
			
			if (priority >= list[i].priority) 
			{
				position = i;
				break;
			}
		}
		
		processObject = new ProcessObject();
		processObject.listener = object;
		processObject.priority = priority;
		
		if (position < 0 || position >= len) 
		{
			list.push(processObject);
		}
		else
		{
			list.splice(position, 0, processObject);
		}
	}
	
	// 移除对象
	private function removeObject(object:*, list:Vector.<ProcessObject>):void 
	{
		var len:int = list.length;
		for (var i:int = 0; i < len; i++) 
		{
			if (!list[i]) continue;
			
			if (list[i].listener == object) 
			{
				if (m_duringAdvance)
				{
					list[i] = null;
					m_needPurgeEmpty = true;
				}
				else {
					list.splice(i, 1);                        
				}
				
				m_numProcess--;
				return;
			}
		}	
		trace("RemoveProcessObject", "This object has not been added to the process manager.");
	}
	
	
	// [Event]
	// 逐帧
	private function ____onEnterFrame(e:Event):void
	{
		var t:int;
		var deltaTime:Number;
		
		t = getTimer();
		
		// 初次跳过
		if (m_oldTime < 0)
		{
			m_oldTime = t;
			return;
		}
		
		deltaTime = (t - m_oldTime) * m_timeScale;
		advance(deltaTime);
		m_oldTime = t;
	}
	
	
	// 更新
	
	// [param] - [deltaTime]		间隔时间(ms)
	// [param] - [suppressSafety]	禁止安全模式
	private function advance(deltaTime:Number, suppressSafety:Boolean = false):void
	{
		var lenT:int, lenA:int, t:int, tickCount:int, i:int;	
		var processObject:ProcessObject;
		
		m_elapsed += deltaTime;

		// 移除空白
		if (m_needPurgeEmpty)
		{
			for (i = m_frameObjects.length - 1; i >= 0; i--)
			{
				if (!m_frameObjects[i]) m_frameObjects.splice(i, 1);
			}
			for (i = m_tickedObjects.length - 1; i >= 0 ; i--)
			{                    
				if (!m_tickedObjects[i]) m_tickedObjects.splice(i, 1);
			}
			m_needPurgeEmpty = false;
			
			if (m_numProcess <= 0)
			{
				stop();
			}
		}
		
		// 有待加入对象
		if(m_needAdded)
		{
			for (i = cachedF.length - 1; i >= 0; i--)
			{
				processObject = cachedF.pop();
				_insertObject(processObject.listener, processObject.priority, m_frameObjects);
			}
			for (i = cachedT.length - 1; i >= 0 ; i--)
			{                    
				processObject = cachedT.pop();
				_insertObject(processObject.listener, processObject.priority, m_tickedObjects);
			}
			m_needAdded = false;
		}
		
		// Tick
		//!!!!!!!!!!!!!!!!!!!!!!!
		while (m_elapsed >= TICK_RATE_MS && (suppressSafety || tickCount < MAX_TICKS_PER_FRAME))
		{
			m_duringAdvance = true;
			lenT = m_tickedObjects.length;
			for (i = 0; i < lenT; i++) 
			{
				(m_tickedObjects[i].listener as ITickObject).onTick(TICK_RATE_MS);
			}
			m_duringAdvance = false;
			
			m_elapsed -= TICK_RATE_MS;
			tickCount++;
		}
		
		// 警告
		if (tickCount >= MAX_TICKS_PER_FRAME && !suppressSafety) 
		{
			trace("advance", "Exceeded maximum number of ticks for frame (" + m_elapsed.toFixed() + "ms dropped) .");
			m_elapsed = 0;
		}
		
		// 确保不会落后太远，预防短时间内帧率降低造成影响。
		m_elapsed = DesN.clamp(m_elapsed, 0, 300);            
		
		// Frame
		//!!!!!!!!!!!!!!!!!!!!!!!
		m_duringAdvance = true;
		lenA = m_frameObjects.length;
		for (i = 0; i < lenA; i++)
		{
			(m_frameObjects[i].listener as IFrameObject).onFrame(deltaTime);
		}
		m_duringAdvance = false;
	}
	
	
	
	
	
	//======================
	// Const
	//======================
	
	
	ns_despair static const TICKS_PER_SECOND:int = 30;	// 每秒计时次数

	ns_despair static const TICK_RATE_MS:Number = ((1.0 / TICKS_PER_SECOND * 10000) >> 0) * 0.1;	// 计时间隔(ms)

	ns_despair static const MAX_TICKS_PER_FRAME:int = 8;	// 每帧最大计时次数

	
	
	
	//======================
	// Member
	//======================
	

	ns_despair static var shape:Shape = new Shape();  // 逐帧侦听

	ns_despair var m_frameObjects:Vector.<ProcessObject> = new Vector.<ProcessObject>();	// 动画对象列表
	
	ns_despair var m_tickedObjects:Vector.<ProcessObject> = new Vector.<ProcessObject>();	// 计时对象列表

	ns_despair var cachedF:Vector.<ProcessObject> = new Vector.<ProcessObject>();	// 待加入动画对象列表
	
	ns_despair var cachedT:Vector.<ProcessObject> = new Vector.<ProcessObject>();	// 待加入计时对象列表
	
	
	
	
	//======================
	// Cached Object
	//======================
	

	ns_despair var m_numProcess:int;  // 进程对象总数

	ns_despair var m_timeScale:Number = 1.0;  // 时间速率倍数(可改变运行速度)

	ns_despair var m_elapsed:Number = 0.0;
	
	ns_despair var m_oldTime:int;
	
	ns_despair var m_started:Boolean;	// 是否已启动
	
	ns_despair var m_needAdded:Boolean;	// 需要净化列表空位
	
	ns_despair var m_needPurgeEmpty:Boolean;	// 需要净化列表空位
	
	ns_despair var m_duringAdvance:Boolean;	// 更新中

	
	

}
}

final class ProcessObject
{
    public var listener:* = null;
    public var priority:Number = 0.0;
}
